﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Text;
using System.Web;
using CSVideoUploader.IO;

namespace CSVideoUploader.Http
{
    /// <summary>
    /// Http客户端类
    /// 通过封装HttpWebRequest和HttpWebResponse实现，并使用CookieContainer进行cookie管理
    /// </summary>
    class HttpClient
    {
        #region 常量定义
        /// <summary>用户代理标识</summary>
        private const string USER_AGENT = "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)";
        /// <summary>行分隔符</summary>
        private const string CRLF = "\r\n";
        #endregion

        #region 变量部分
        /// <summary>客户端使用的编码</summary>
        private Encoding encoding = null;
        /// <summary>Cookie存储器</summary>
        private CookieContainer cookies = null;
        #endregion

        public HttpClient()
        {
            // 初始化cookie表
            cookies = new CookieContainer();
            // 默认使用U8编码
            encoding = Encoding.UTF8;
        }

        public HttpClient(string charset)
        {
            // 初始化cookie表
            cookies = new CookieContainer();
            // 使用指定的编码，缺省将使用UTF8
            // 仅urlencoded使用此编码，multipart还是要用UTF8
            encoding = SafetyGetEncoding(charset, Encoding.UTF8);
        }

        private HttpWebRequest CreateRequest(string url, Dictionary<string, string> headers)
        {
            HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);
            req.UserAgent = USER_AGENT;
            req.ProtocolVersion = HttpVersion.Version11;
            req.AllowAutoRedirect = true;
            req.Timeout = System.Threading.Timeout.Infinite;
            req.CookieContainer = cookies;
            // 不使用代理
            req.Proxy = null;

            // 附加请求头
            if (headers != null)
            {
                foreach (KeyValuePair<string, string> item in headers)
                {
                    if (item.Key == "Referer")
                    {
                        req.Referer = item.Value;
                    }
                    else
                    {
                        req.Headers.Add(item.Key, item.Value);
                    }
                }
            }

            return req;
        }

        private Encoding SafetyGetEncoding(String name, Encoding defaultEncoding)
        {
            Encoding enc = defaultEncoding;
            try
            {
                enc = Encoding.GetEncoding(name);
            }
            catch (Exception){}

            return enc;
        }

        /// <summary>
        /// 发送Get请求
        /// </summary>
        /// <param name="url">请求地址</param>
        /// <returns></returns>
        public string Get(string url)
        {
            return Get(url, null);
        }

        /// <summary>
        /// 发送Get请求
        /// </summary>
        /// <param name="url">请求地址</param>
        /// <param name="headers">附加请求头</param>
        /// <returns></returns>
        public string Get(string url, Dictionary<string, string> headers)
        {
            // 创建http请求
            HttpWebRequest req = CreateRequest(url, headers);
            req.Method = "GET";

            // 获得响应
            HttpWebResponse resp = (HttpWebResponse)req.GetResponse();
            // 保存cookie
            cookies.Add(resp.Cookies);
            // 读取结果
            Encoding enc = SafetyGetEncoding(resp.CharacterSet, Encoding.UTF8);
            StreamReader reader = new StreamReader(resp.GetResponseStream(), enc);
            string result = reader.ReadToEnd();
            reader.Close();

            return result;
        }

        /// <summary>
        /// 发送Post请求
        /// </summary>
        /// <param name="url">请求地址</param>
        /// <param name="parameters">参数表</param>
        /// <returns></returns>
        public string Post(string url, Dictionary<string, string> parameters)
        {
            return Post(url, parameters, null);
        }

        /// <summary>
        /// 发送Post请求
        /// </summary>
        /// <param name="url">请求地址</param>
        /// <param name="parameters">参数表</param>
        /// <param name="headers">附加请求头</param>
        /// <returns></returns>
        public string Post(string url, Dictionary<string, string> parameters, Dictionary<string, string> headers)
        {
            // 创建http请求
            HttpWebRequest req = CreateRequest(url, headers);
            req.Method = "POST";
            req.ContentType = "application/x-www-form-urlencoded";

            // 构造表单数据
            StringBuilder buf = new StringBuilder();
            foreach (KeyValuePair<string, string> item in parameters)
            {
                buf.Append(item.Key).Append("=")
                    .Append(HttpUtility.UrlEncode(item.Value, encoding))
                    .Append("&");
            }
            buf.Remove(buf.Length - 1, 1);
            byte[] formData = Encoding.UTF8.GetBytes(buf.ToString());

            // 设置数据长度
            req.ContentLength = formData.Length;

            // 写入表达数据
            MyStreamWriter writer = new MyStreamWriter(req.GetRequestStream());
            writer.WriteBytes(formData);
            writer.Close();

            // 获取请求
            HttpWebResponse resp = (HttpWebResponse)req.GetResponse();
            // 保存cookie
            cookies.Add(resp.Cookies);

            // 读取结果
            Encoding enc = SafetyGetEncoding(resp.CharacterSet, Encoding.UTF8);
            StreamReader reader = new StreamReader(resp.GetResponseStream(), enc);
            string result = reader.ReadToEnd();
            reader.Close();

            return result;
        }

        private string CreateBoundary()
        {
            return Convert.ToString(DateTime.Now.Ticks, 16);
        }

        /// <summary>
        /// 用Post请求提交文件
        /// 目前只实现提交一个文件（够用了）
        /// </summary>
        /// <param name="url">URL地址</param>
        /// <param name="parameters">字符串参数</param>
        /// <param name="fileFieldName">文件域名称</param>
        /// <param name="file">文件流</param>
        /// <param name="handler">上传监听器</param>
        /// <returns></returns>
        public string PostFile(string url, Dictionary<string, string> parameters,
            string fileFieldName, FileStream file, IUploadProgressListener handler)
        {
            // 生成分隔符
            string boundary = CreateBoundary();

            // 创建http请求
            HttpWebRequest req = CreateRequest(url, null); ;
            req.Method = "POST";
            req.ContentType = "multipart/form-data; boundary=" + boundary;
            req.AllowWriteStreamBuffering = false;
            req.KeepAlive = false;

            // 开头部分
            StringBuilder buf = new StringBuilder();
            buf.Append("--").Append(boundary).Append(CRLF)
                .Append("Content-Disposition: form-data; name=\"").Append(fileFieldName)
                .Append("\"; filename=\"").Append(Path.GetFileName(file.Name)).Append("\"").Append(CRLF)
                .Append("Content-Type: application/octet-stream").Append(CRLF).Append(CRLF);
            byte[] data1 = Encoding.UTF8.GetBytes(buf.ToString());

            // 结尾部分
            buf = new StringBuilder();
            if (parameters != null)
            {
                // 追加其他字符串参数
                foreach (KeyValuePair<string, string> p in parameters)
                {
                    buf.Append("--").Append(boundary).Append(CRLF);
                    buf.Append("Content-Disposition: form-data; name=").Append(p.Key).Append("\"").Append(CRLF).Append(CRLF)
                        .Append(p.Value).Append(CRLF);
                }
            }
            buf.Append("--").Append(boundary).Append("--");
            byte[] data2 = Encoding.UTF8.GetBytes(buf.ToString());

            // 设置请求长度
            req.ContentLength = data1.Length + file.Length + data2.Length;

            // 开始写入请求内容
            MyStreamWriter writer = new MyStreamWriter(req.GetRequestStream());
            // 写入开头文本
            writer.WriteBytes(data1);
            writer.Flush();
            // 读取文件并写入
            int readLength = 0;
            long writeLength = 0;
            if (handler != null)
                handler.Start(file.Length);
            do
            {
                byte[] block = new byte[4096];
                readLength = file.Read(block, 0, 4096);
                writer.WriteBytes(block, 0, readLength);
                writer.Flush();
                // 统计写入的数量
                writeLength += readLength;
                // 通知监听器
                if (handler != null)
                    handler.Progress(writeLength);
            } while (readLength > 0);
            if (handler != null)
                handler.Complete();
            // 写入结尾文本
            writer.WriteBytes(data2);
            writer.Flush();
            writer.Close();

            HttpWebResponse resp = (HttpWebResponse)req.GetResponse();
            // 保存cookie
            cookies.Add(resp.Cookies);

            // 读取结果
            Encoding enc = SafetyGetEncoding(resp.CharacterSet, Encoding.UTF8);
            StreamReader reader = new StreamReader(resp.GetResponseStream(), enc);
            string result = reader.ReadToEnd();
            reader.Close();

            return result;
        }
    }
}
